<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>Document</title>
</head>
<body>
	<script type="text/javascript">
		function* genDemo() {
			console.log("开始执行第一段")
			yield 'generator 1'

			console.log("开始执行第二段")
			yield 'generator 2'

			console.log("开始执行第三段")
			yield 'generator 3'

			console.log("执行结束")
			return 'generator 3'
		}

		/*console.log('main 0')
		let gen = genDemo()
		console.log(gen.next().value)
		console.log('main 1')
		console.log(gen.next().value)
		console.log('main 2')
		console.log(gen.next().value)
		console.log('main 3')
		console.log(gen.next().value)
		console.log('main 4')*/
/*
通过调用生成器函数 genDemo 来创建一个 协程 gen，创建之后，gen 协程并没有立即执行。
要让 gen 协程执行，需要通过调用 gen.next。
当协程正在执行的时候，可以 通过 yield 关键字来暂停 gen 协程的执行，并返回主要信息给父协程。
如果协程在执行期间，遇到了 return 关键字，那么 JS 引擎会结束当前协程，并将 return 后面的内容返回给父协程。
*/
	/*
	  通过bind绑定后的函数可以直接调用，也可以通过 new 操作符来调用
	  直接调用时，this指向bind绑定时的对象
	  通过 new 操作符调用时，之前通过 bind 方法绑定的 this 指向消失了，构造器的属性和原型的属性都有顺利继承
	  因为 在执行 new 操作符方法时，回在内部创建一个新的对象，函数的内部的this会指向新创建的实例对象
	  所以，我们在手写 bind 方法时，返回的函数需要来考虑到是自身调用还是通过 new 操作符调用，因为两者的this指向不同
	  因为构造函数在 通过 new 运行时，内部的 constructor 属性指向构造函数本身，可以通过 constructor的指向，判断函数的调用方式。
	*/
	Function.prototype.bindFn = function(obj) {
		// 获取调用 bind 方法的函数
		let fn = this
		// 获取传入 bind 方法的参数
		let arg = Array.prototype.slice(arguments, 1)
		// 返回一个待执行的函数
		let bound = function() {
			// 实现函数柯里化
			let param = Array.prototype.slice(arguments)
			// 判断函数的调用方式
			fn.apply(this.constructor === fn ? this : obj, arg.concat(param))
		}
		// 原型链继承
		bound.prototype = fn.prototype
		// 返回一个待执行函数
		return bound
	}

	Function.prototype.myBind = function(...args){
		let fn = this
		let context = args[0]
		let arg = args.slice(1)
		let myBindFn = function(...params){
			let dataParam = arg.concat(params)
			fn.apply(this.constructor === fn ? this : context, dataParam)
		}
		myBindFn.prototype = fn.prototype
		return myBindFn
	}
	var z = 0;
	var obj = {
	    z: 1
	};

	function fn(x, y) {
	    this.name = '听风是风';
	    console.log(this.z);
	    console.log(x);
	    console.log(y);
	};
	fn.prototype.age = 26;

	var bound = fn.myBind(obj, 2);
	var person = new bound(3); //undefined 2 3

	console.log(person.name); //听风是风
	console.log(person.age); //26
	person.__proto__.age = 18;
	var person = new fn();
	console.log(person.age); //26


	Function.prototype.bindFunc = function(...args){
		let fn = this // 获取调用 bind 方法的函数
		let context = args[0] // 获取 bind 方法的第一个参数，也就是需要绑定的上下文
		let param1 = args.slice(1) // 获取去除绑定上下文的剩余参数
		let bound = function() {
			
		}
	}
	</script>
</body>
</html>